// Copyright (c) 2021 Presto Labs Pte. Ltd.
// Author: daniel

#include "coin2/exchange/lmax_digital/api_order/native_private_client.h"

#include <memory>

#include "coin2/base/time.h"
#include "coin2/exchange/base/api_util/url_params_builder.h"
#include "coin2/exchange/base/order/order.h"

LmaxdigitalNativePrivateClient::LmaxdigitalNativePrivateClient(
    const NativeClientConfig& config_override) {
  NativeClientConfig config;
  config.set_rest_host("account-api.london-digital.lmax.com");
  config.set_rest_host_port(443);
  config.MergeFrom(config_override);
  LOG(INFO) << "[LmaxdigitalNativePrivateClient] config: " << config.DebugString();

  auths_.Construct<LmaxdigitalRestAuth, NativeClientConfig>(config);
}

void LmaxdigitalNativePrivateClient::Prepare() {
  mb_->Subscribe("lmaxdigital_spot/token", [this](const std::string&, void* data) {
    const std::string* token = reinterpret_cast<const std::string*>(data);
    token_ = *token;
    LOG(INFO) << "token received: " << token_;
    dynamic_cast<LmaxdigitalBaseAuth*>(GetAuth())->SetToken(token_);
    last_update_token_ts_ = GetCurrentTimestamp();
  });
}

std::shared_ptr<AsioHttpContext> LmaxdigitalNativePrivateClient::QueryAuth() {
  auto timestamp = GetCurrentTimestamp();
  if (last_update_token_ts_ > 0 && last_update_token_ts_ + 300'000'000'000LL > timestamp) {
    return {};
  }
  UrlParamsBuilder builder;
  auto* context =
      auths_.GetRandom()->CreateRequestByPostWithSignature("/v1/authenticate", &builder);
  context->query_type = OrderSubTopicId::LISTEN_KEY;
  return std::shared_ptr<AsioHttpContext>(context);
}

std::shared_ptr<AsioHttpContext> LmaxdigitalNativePrivateClient::QueryAccountBalance() {
  if (token_.empty()) {
    return {};
  }
  UrlParamsBuilder builder;
  auto* context = GetAuth()->CreateRequestByGetWithSignature("/v1/account/wallets", &builder);

  context->query_type = OrderSubTopicId::REST_ACCOUNT_BALANCE;
  return std::shared_ptr<AsioHttpContext>(context);
}

std::shared_ptr<AsioHttpContext> LmaxdigitalNativePrivateClient::QueryOpenOrders() {
  if (token_.empty()) {
    return {};
  }
  UrlParamsBuilder builder;
  auto* context =
      GetAuth()->CreateRequestByGetWithSignature("/v1/account/working-orders", &builder);

  context->query_type = OrderSubTopicId::REST_OPEN_ORDERS;
  return std::shared_ptr<AsioHttpContext>(context);
}

std::shared_ptr<AsioHttpContext> LmaxdigitalNativePrivateClient::PlaceOrderNorm(
    const OrderExecution& order_exe) {
  // submit order with rest api is unsupported
  LOG(ERROR) << "submit order with rest api is unsupported";
  return {};
}

std::shared_ptr<AsioHttpContext> LmaxdigitalNativePrivateClient::CancelOrderNorm(
    const OrderExecution& order_exe) {
  // cancel order with rest api is unsupported
  LOG(ERROR) << "cancel order with rest api is unsupported";
  return {};
}

std::shared_ptr<AsioHttpContext> LmaxdigitalNativePrivateClient::SubmitOrderExecution(
    const OrderExecutionProto& order) {
  switch (order.type()) {
    case OrderExecutionProto::SUBMIT_ORDER: {
      return nullptr;
    }
    case OrderExecutionProto::CANCEL_ORDER: {
      return nullptr;
    }
    default: {
      return nullptr;
    }
  }
}

std::shared_ptr<AsioHttpContext> LmaxdigitalNativePrivateClient::SubmitRestQuery(
    const RestQueryProto& query) {
  switch (query.type()) {
    case RestQueryProto::QUERY_ACCOUNT_BALANCE: {
      return QueryAccountBalance();
    }
    case RestQueryProto::QUERY_OPEN_ORDERS: {
      return QueryOpenOrders();
    }
    default: {
      return nullptr;
    }
  }
}
